package com.xu.sso.web.service.impl;

import com.xu.sso.core.config.SSOConfig;
import com.xu.sso.core.enums.ErrorMessage;
import com.xu.sso.core.exception.SSOException;
import com.xu.sso.core.model.AppPathRole;
import com.xu.sso.core.model.BaseResponse;
import com.xu.sso.core.utils.ExceptionUtil;
import com.xu.sso.core.utils.RedisUtil;
import com.xu.sso.db.model.base.ApiAuth;
import com.xu.sso.db.model.base.App;
import com.xu.sso.db.model.base.Department;
import com.xu.sso.db.model.base.ResourcesRole;
import com.xu.sso.db.service.ApiAuthDBService;
import com.xu.sso.db.service.AppDBService;
import com.xu.sso.db.service.DepartmentDBService;
import com.xu.sso.db.service.ResourcesDBService;
import com.xu.sso.web.model.request.UpdateDepRequest;
import com.xu.sso.web.model.response.ApiKeyResponse;
import com.xu.sso.web.service.ManageService;
import com.xu.sso.web.service.convert.ManageConvert;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ManageServiceImpl implements ManageService {

    @Autowired
    private DepartmentDBService departmentDBService;
    @Autowired
    private ApiAuthDBService apiAuthDBService;
    @Autowired
    private AppDBService appDBService;
    @Autowired
    private ResourcesDBService resourcesDBService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public List<Department> findAllDepartment() {
        return departmentDBService.findAllDepartment();
    }

    @Override
    public Department findDepartmentById(Integer id) {
        return departmentDBService.findDepartmentById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse createDepartment(Department department) throws SSOException {
        Department oldDep = departmentDBService.findDepartmentByName(department.getDepName());
        if (null != oldDep) {
            throw ExceptionUtil.createException(ErrorMessage.DepExist);
        }
        int i = departmentDBService.createDepartment(department);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.AddDepError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse updateDepartment(UpdateDepRequest request) throws SSOException {
        if (!request.getOldName().equals(request.getDepName())) {
            Department oldDep = departmentDBService.findDepartmentByName(request.getDepName());
            if (null != oldDep) {
                throw ExceptionUtil.createException(ErrorMessage.DepExist);
            }
        }
        Department department = ManageConvert.convert(request);
        int i = departmentDBService.updateDepartment(department);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.UpdateDepError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse deleteDep(Integer id) throws SSOException {
        int i = departmentDBService.deleteById(id);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.DeleteDepError);
        }
        return new BaseResponse();
    }

    @Override
    public ApiAuth findApiAuthById(Integer id) {
        return apiAuthDBService.findApiAuthId(id);
    }

    @Override
    public List<ApiAuth> findAllApiAuths() {
        return apiAuthDBService.findAllApiAuth();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse createApiAuth(ApiAuth apiAuth) throws SSOException {
        App app = appDBService.findAppByAppId(apiAuth.getAppId());
        if (null == app) {
            throw ExceptionUtil.createException(ErrorMessage.AppNotExist);
        }
        apiAuth.setAppName(app.getAppName());
        int i = apiAuthDBService.createApiAuth(apiAuth);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.AddApiAuthError);
        }
        return new BaseResponse();
    }

    @Override
    public BaseResponse updateApiAuth(ApiAuth apiAuth) throws SSOException {
        int i = apiAuthDBService.updateApiAuth(apiAuth);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.UpdateApiAuthError);
        }
        return new BaseResponse();
    }

    @Override
    public ApiKeyResponse createApiKey() throws SSOException {
        ApiKeyResponse response = new ApiKeyResponse();
        response.setKey(RandomStringUtils.randomAlphanumeric(32));
        return response;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse changeApiStatus(Integer id, String status) throws SSOException {
        int i = apiAuthDBService.updateApiAuthStatus(id, status);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.ChangeApiStatusError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse deleteApiAuth(Integer id) throws SSOException {
        int i = apiAuthDBService.deleteApiAuth(id);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.DeleteApiAuthError);
        }
        return new BaseResponse();
    }

    @Override
    public BaseResponse refreshRedis() throws SSOException {
        List<ResourcesRole> resourcesRoles = resourcesDBService.findAllResourcesRole();
        Set<String> appIds = resourcesRoles.stream().map(ResourcesRole::getAppId).collect(Collectors.toSet());
        for (String appId : appIds) {
            List<AppPathRole> pathRoles = appDBService.findAppPermissions(appId);
            boolean result = redisUtil.set(SSOConfig.REDIS_SET + appId, pathRoles);
            if (!result) {
                throw ExceptionUtil.createException(ErrorMessage.RedisError);
            }
        }
        return new BaseResponse();
    }
}
